#include "SocketMgrLinux.h"

#include "Socket.h"
#include "ListenSocketLinux.h"

SocketMgr::SocketMgr(TeNetCall* pkCall)
{
    m_pkCall = pkCall;
    memset(m_pkFds, 0, sizeof(void*) * SOCKET_HOLDER_SIZE);

    m_kSocketBuffer.Allocate(16);
}
SocketMgr::~SocketMgr()
{
    close(m_EpollFd);
}

bool SocketMgr::Init()
{
    m_EpollFd = epoll_create(SOCKET_HOLDER_SIZE);
    if(m_EpollFd == -1)
    {
        printf("Could not create epoll fd (/dev/epoll).");
        return false;
    }
    m_pkSocketThread = new SocketWorkerThread(this);
    return true;
}

void SocketMgr::Update()
{
    ulong uUseCnt = m_kSocketBuffer.GetUsedCnt();
    ulong uLen = uUseCnt > PROCESS_NET_DATA?PROCESS_NET_DATA:uUseCnt;
    uint8 buf[PROCESS_NET_DATA] = {};

    if(!m_kSocketBuffer.ReadBuffer(&buf,uLen) || uUseCnt == 0)
    {
        return;
    }
    printf("SocketMgr::Update() Recv Data.[%d]\n",uUseCnt);
    for(ulong i = 0;i < uLen;i += sizeof(void*))
    {
        ulong ulAddr = 0;
        memcpy((void*)&ulAddr,&buf[i],sizeof(void*));
        printf("SocketMgr::Update() Socket Address:%llu\n",ulAddr);
        Socket* s = (Socket*)ulAddr;
        if(s)
        {
            printf("s->OnRead begin()[%llu].\n",s);
            s->OnRead();
            printf("s->OnRead end()[%llu].\n",s);
        }
    }
}

void SocketMgr::AddSocket(Socket* s)
{
    m_pkFds[s->GetFd()] = s;

    struct epoll_event ev;
    memset(&ev, 0, sizeof(epoll_event));
    ev.events =  EPOLLOUT | EPOLLIN | EPOLLET | EPOLLERR | EPOLLHUP | EPOLLPRI;
    ev.data.ptr = s;
    if(epoll_ctl(m_EpollFd,EPOLL_CTL_ADD,s->GetFd(),&ev))
    {
        printf("epoll", "Could not add event to epoll set on fd %u",s->GetFd());
    }
    printf("SocketMgr::AddSocket[%llu][%d].\n",s,s->GetFd());
}

void SocketMgr::RemoveSocket(Socket* s)
{
    if(m_pkFds[s->GetFd()] != s)
    {
        printf("epoll", "Could not remove fd %u from the set due to it not existing?", s->GetFd());
        return;
    }

    m_pkFds[s->GetFd()] = 0;

    struct epoll_event ev;
    memset(&ev, 0, sizeof(epoll_event));
    //ev.events = EPOLLIN | EPOLLOUT | EPOLLERR | EPOLLHUP | EPOLLONESHOT;
    ev.events = EPOLLERR | EPOLLHUP | EPOLLET;
    ev.data.ptr = s;
    if(epoll_ctl(m_EpollFd, EPOLL_CTL_DEL,s->GetFd(),&ev))
    {
        printf("epoll", "Could not remove fd %u from epoll set, errno %u", s->GetFd(), errno);
    }
    printf("SocketMgr::RemoveSocket[%d].\n",s->GetFd());
}
void SocketMgr::DisConnect(SOCKET sFd)
{
    printf("SocketMgr::DisConnect.\n");
    Socket* s =(Socket*)m_pkFds[sFd];
    if(s)
    {
        s->Disconnect();
    }
}
void SocketMgr::CloseAll()
{
    for(int i = 0; i < SOCKET_HOLDER_SIZE; ++i)
    {
        if(m_pkFds[i] != NULL)
        {
           ((Socket*)m_pkFds[i])->Delete();
        }
    }
}
bool SocketMgr::SendBuffer(SOCKET sFd,void* pData,int iSize)
{
    Socket* s = (Socket*)m_pkFds[sFd];
    if(!s)
    {
        return false;
    }
    s->Send((const uint8*)pData,iSize);
}
void SocketMgr::SpawnWorkerThreads()
{
    int iCount = 1;
    m_pkSocketThread->Start();

}

void SocketMgr::PushSocket(Socket* s)
{
    ulong ulAddr = (ulong)s;
    m_kSocketBuffer.WriteBuffer(&ulAddr,sizeof(s));
    printf("SocketMgr::PushSocket() Socket Address:%llu\n",s);
}

void SocketWorkerThread::Run()
{
    printf("SocketWorkerThread::Run.\n");
    m_bRunning = true;

    while(m_bRunning)
    {
        int iFdCount = epoll_wait(m_pkMgr->GetEpollFd(),m_kEvents,THREAD_EVENT_SIZE,5000);
        for(int i = 0; i < iFdCount; ++i)
        {
            Socket* pkPtr = (Socket*)m_kEvents[i].data.ptr;
            if(!pkPtr)
            {
                printf("SocketWorkerThread::Run() Can`t Find FD.\n");
                continue;
            }
 
            if(m_kEvents[i].events & EPOLLHUP || m_kEvents[i].events & EPOLLERR)
            {
                printf("SocketWorkerThread::Run() DisCnnect().");
                pkPtr->Disconnect();
                continue;
            }
            else if(m_kEvents[i].events & EPOLLIN)
            {
                pkPtr->ReadCallback(0);
            }
            else if(m_kEvents[i].events & EPOLLOUT)
            {
                pkPtr->WriteCallback();
                if(pkPtr->GetSendBuffer().GetUsedCnt() > 0)
                {
                                    
                }
                else
                {
                    pkPtr->PostEvent(EPOLLIN);
                }
            }
        }       
    }
}

